package com.hh.service.impl;

import com.hh.controller.UserController;
import com.hh.mapper.MessageMapper;
import com.hh.pojo.Message;
import com.hh.pojo.MessageModel;
import com.hh.service.MessageService;
import com.hh.utils.ServiceTool;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

@Service
public class MessageServiceImpl implements MessageService {

    @Autowired
    private MessageMapper messageMapper;

    // 新增一种消息 （有 评论、回复（回复评论或者回复 原来的回复）、点赞 和 收藏四种消息类型）
    // map 要新增的消息，里面的字段应该初始化之后传过来
    /*
    map 中包含的 键值对：
    fromUname
    postId
    toUname  消息接收人 可能为空null， 需要检查一下
    prId
    msgType
    * */
    // 返回值 messageModel 200 消息发送正常
    private MessageModel addMsg(Map<String, Object> map){
        MessageModel rs = new MessageModel(200, "评论消息发送成功！");

        // 检查是否已登录
        if (map.get("fromUname") == null){
            rs.setResult_code(605);
            rs.setMsg("用户未登录！消息发送失败！");
        }else {
            try {
                if (messageMapper.sendMsg(map) < 1){
                    rs.setResult_code(300);
                    rs.setMsg("消息添加失败，（数据库插入失败。）");
                }
            }catch (Exception e){
                rs.setResult_code(303);
                rs.setMsg("消息发送失败，数据库插入（消息）发生异常。");
                e.printStackTrace();
            }
        }

        return rs;
    }


    // 当前登录用户发起一条 评论帖子的消息
    @Override
    public MessageModel addPostReplyMsg(int postId, String toUname, int prId, HttpServletRequest request) {
        String fromUname = UserController.getCurrentUser(request) == null ? null : UserController.getCurrentUser(request).getUname();
        Map<String, Object> map = new HashMap<>();

        // 初始化消息内容 （评论）
        map.put("fromUname", fromUname);  // 发送人 如果未登录，传的是null
        map.put("postId", postId);
        map.put("toUname", toUname);
        map.put("prId", prId);
        map.put("msgType", (byte)1);
//        message.setFromUname(fromUname);
//        message.setPostId(postId);
//        message.setToUname(toUname);
//        message.setPrId(prId);
//        message.setMsgType((byte) 1);

        return addMsg(map);
    }

    @Override
    public MessageModel addReplyReplyMsg(String fromUname, int postId, String toUname, int prId, int rrId, int inrrId) {
        Map<String, Object> map = new HashMap<>();

        // 初始化消息内容 （评论）
        map.put("fromUname", fromUname);  // 发送人 如果未登录，传的是null
        map.put("postId", postId);
        map.put("toUname", toUname);
        map.put("msgType", (byte)2);
        map.put("rrId", rrId);

        /*
        （因为消息类型必取其一，所以评论id 和 二次回复id 必有一个为0、 一个不为0）如果评论id为0表示这个回复类型是 回复 给回复，则不把评论id 封装到map；
        否则（表示是回复给 评论），不把二次回复id 封进 map。
        * */
        if (prId == 0){ // 回复给 回复
            map.put("inrrId", inrrId);
        }else { // 回复给 评论
            map.put("prId", prId);
        }

        return addMsg(map);
    }

    @Override
    public MessageModel addSubscribeMsg(String fromUname, String toUname, int postId, int prId) {
        Map<String, Object> map = new HashMap<>();

        // 初始化消息内容 （评论）
        map.put("fromUname", fromUname);  // 发送人 如果未登录，传的是null
        map.put("toUname", toUname);
        map.put("postId", postId); // 无论点赞什么，都要把帖子id传进来
        map.put("msgType", (byte)3);
        if (prId != 0){ // 如果点赞的是帖子
            map.put("prId", prId);
        }

        return addMsg(map);
    }

    @Override
    public MessageModel addCollectMsg(String fromUname, String toUname, int postId) {
        Map<String, Object> map = new HashMap<>();

        // 初始化消息内容 （评论）
        map.put("fromUname", fromUname);  // 发送人 如果未登录，传的是null
        map.put("toUname", toUname);
        map.put("postId", postId);
        map.put("msgType", (byte)4);

        return addMsg(map);
    }

    @Override
    public Map<String, Object> getUserMsgsByType(int msgType, String uname) {
        HashMap<String, Object> map = new HashMap<>(); // 结果map
        List<Message> list = null; // 结果list
        MessageModel rs = new MessageModel(200, "消息列表获取成功！"); // 消息列表获取结果

        // 判断用户是否已登录
        if (uname == null){
            rs.setResult_code(605);
            rs.setMsg("当前用户未登录！请先登录再获取消息列表！");
        }else {
            try {
                // 根据不同的消息类型 获取用户消息列表
                switch (msgType){
                    case 1: // 评论
                        list = messageMapper.getCommentListByUser(uname);
                        break;
                    case 2: // 回复
                        // 获取回复 评论的 消息列表 (通知时间倒序)
                        List<Message> commentReplyList = messageMapper.getCommentReplyListByUser(uname);
                        // 获取回复 回复的 消息列表（通知时间倒序）
                        List<Message> replyReplyList = messageMapper.getReplyReplyListByUser(uname);

                        // 按照通知事件倒序 将两个消息列表排序  作为最终的结果列表
                        list = new LinkedList<>();
                        for (int p1 = 0, p2 = 0; p1 < commentReplyList.size() || p2 < replyReplyList.size();){
                            // 如果一方指针到了尽头就直接把另一方的加进来
                            if (p1 == commentReplyList.size()){
                                list.add(replyReplyList.get(p2));
                                p2++;
                            }else if (p2 == replyReplyList.size()){
                                list.add(commentReplyList.get(p1));
                                p1++;
                            }else {
                                // 把早的放进来并移动  指针
                                if (commentReplyList.get(p1).getInformTime().after(replyReplyList.get(p2).getInformTime())){
                                    list.add(commentReplyList.get(p1));
                                    p1++;
                                }else {
                                    list.add(replyReplyList.get(p2));
                                    p2++;
                                }
                            }
                        }
                        break;
                    case 3: // 点赞
                        // 点赞分点赞评论和帖子，直接一次性整体获取； 如果是点赞帖子，则结果message的 postReply 变量为 空
                        list = messageMapper.getSbcListByUser(uname);
                        break;
                    case 4: // 收藏
                        list = messageMapper.getCltListByUser(uname);
                        break;
                    default:
                        return ServiceTool.getListWrong();
                }
            }catch (Exception e){  /*数据库查询发生异常*/
                e.printStackTrace();
                return ServiceTool.getListWrong();
            }
        }

        map.put("rs", rs);
        map.put("list", list);
        return map;
    }

    @Override
    public Map<String, Object> getUserMsgUnreadNums(String uname) {
        Map<String, Object> map = new HashMap<>(); // 结果map
        MessageModel rs = new MessageModel(200, "未读消息数量获取成功！"); // 未读消息数量获取结果
        HashMap<String, Object> mapperMap; // mapper 层的参数map

        // 判断用户是否已登录
        if (uname == null){
            rs.setResult_code(605);
            rs.setMsg("当前用户未登录！请先登录再获取消息未读数！");
        }else {
            try {
                mapperMap  = new HashMap<>();
                mapperMap.put("toUname", uname);

                // 分别获取四种 消息的未读数
                // 评论
                mapperMap.put("msgType", 1);
                map.put("cmtNum", messageMapper.getUserUnreadenMsgNumByType(mapperMap));
                // 回复
                mapperMap.replace("msgType", 2);
                map.put("rplNum", messageMapper.getUserUnreadenMsgNumByType(mapperMap));
                // 点赞
                mapperMap.replace("msgType", 3);
                map.put("sbcNum", messageMapper.getUserUnreadenMsgNumByType(mapperMap));
                // 收藏
                mapperMap.replace("msgType", 4);
                map.put("cltNum", messageMapper.getUserUnreadenMsgNumByType(mapperMap));
            }catch (Exception e){  /*数据库查询发生异常*/
                e.printStackTrace();
                rs.setMsg("用户消息未读数查询发生异常！ 数据库查询失败！");
                rs.setResult_code(303);
            }
        }

        map.put("rs", rs);
        return map;
    }

    @Override
    public MessageModel setUserMsgsReadByType(String uname, int msgType) {
        MessageModel rs = new MessageModel(200, "消息设置为已读成功！"); // 设置结果

        // 判断用户是否已登录
        if (uname == null){
            rs.setResult_code(605);
            rs.setMsg("当前用户未登录！请先登录再设置消息为已读！");
        }else {
            try {
                // 如果受影响行数 < 1 则表示有异常
                if (messageMapper.setMsgsReaden(msgType, uname) < 1){
                    rs.setResult_code(300);
                    rs.setMsg("调整失败，（数据库更新失败。）");
                }
            }catch (Exception e){  /*数据库查询发生异常*/
                e.printStackTrace();
                rs.setMsg("用户消息未读设置为已读发生异常！ 数据库更新失败！");
                rs.setResult_code(303);
            }
        }

        return rs;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout=36000,rollbackFor=Exception.class)
    public MessageModel truncateUserMsgByType(String uname, int msgType) {
        StringBuilder rsMsg = new StringBuilder("成功清空所有");
        MessageModel rs = new MessageModel(200); // 设置结果

        // 拼接消息信息
        switch (msgType){
            case 1:
                rsMsg.append("【评论】");
                break;
            case 2:
                rsMsg.append("【回复】");
                break;
            case 3:
                rsMsg.append("【点赞】");
                break;
            case 4:
                rsMsg.append("【收藏】");
                break;
            default:
                System.err.println("消息类型异常！");
        }
        rsMsg.append("消息！");
        rs.setMsg(rsMsg.toString());

        // 判断用户是否已登录
        if (uname == null){
            rs.setResult_code(605);
            rs.setMsg("当前用户未登录！请先登录再清空消息！");
        }else {
            try {
                // 如果受影响行数 < 1 则表示有异常
                if (messageMapper.truncateUserMsgByType(msgType, uname) < 1){
                    rs.setResult_code(301);
                    rs.setMsg("清空的消息数量为 0 !");
                }
            }catch (Exception e){  /*数据库查询发生异常*/
                e.printStackTrace();
                rs.setMsg("清空用户消息发生异常！ 数据库删除失败！");
                rs.setResult_code(303);
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();  //由于手动catch了异常， 此处需要手动进行事务回滚
            }
        }

        return rs;
    }

    // 测试默认构造获取对象属性。
    @Test
    public void testObj(){
        Message message = new Message();

        message.getFromUser().setUname("uname");

        System.out.println(message.getFromUser().getUname());
    }

    // 测试sout 和 serr
    @Test
    public void testErr(){
        System.out.println("sout");  // 黑色字体
        System.err.println("serr");  // 红色字体
    }
}
